package com.stars.easyms.datasource.support;

import com.alibaba.druid.pool.DruidDataSource;
import com.stars.easyms.datasource.enums.DatabaseType;
import com.stars.easyms.datasource.properties.EasyMsDataSourcePropertiesProcessor;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.util.Collections;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 * <p>className: DruidDataSourceSupport</p>
 * <p>description: DruidDataSource支持类</p>
 *
 * @author guoguifang
 * @version 1.2.1
 * @date 2019-05-14 17:05
 */
@Slf4j
public final class DruidDataSourceSupport implements DataSourceSupport<DruidDataSource> {

    @Override
    public DataSource createDataSource(EasyMsDataSourcePropertiesProcessor propertiesProcessor, DatabaseType databaseType, String driverClassName, boolean isMaster) {
        DruidDataSource baseDataSource = new DruidDataSource();
        baseDataSource.setDbType(databaseType.getDbType());
        baseDataSource.setDriverClassName(driverClassName);
        Properties properties = propertiesProcessor.getProperties(databaseType, isMaster);
        baseDataSource.configFromPropety(properties);
        handleVersionDifferences(baseDataSource, properties);
        return baseDataSource;
    }

    @Override
    public DataSource cloneDataSource(DruidDataSource druidDataSource) {
        return druidDataSource.cloneDruidDataSource();
    }

    @Override
    public void setConnectParams(DruidDataSource druidDataSource, String url, String username, String password) {
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
    }

    @Override
    public boolean isValid(DruidDataSource dataSource) {
        return dataSource.isEnable();
    }

    /**
     * 处理版本差异引起的问题，0.x.x版本无法自动设置部分属性因此需要手动设置
     */
    private void handleVersionDifferences(DruidDataSource druidDataSource, Properties properties) {
        String property = properties.getProperty("druid.name");
        if (property != null) {
            druidDataSource.setName(property);
        }

        property = properties.getProperty("druid.url");
        if (property != null) {
            druidDataSource.setUrl(property);
        }

        property = properties.getProperty("druid.username");
        if (property != null) {
            druidDataSource.setUsername(property);
        }

        property = properties.getProperty("druid.password");
        if (property != null) {
            druidDataSource.setPassword(property);
        }

        property = properties.getProperty("druid.timeBetweenEvictionRunsMillis");
        if (property != null && property.length() > 0) {
            try {
                long value = Long.parseLong(property);
                druidDataSource.setTimeBetweenEvictionRunsMillis(value);
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.timeBetweenEvictionRunsMillis'", e);
            }
        }

        property = properties.getProperty("druid.maxWaitThreadCount");
        if (property != null && property.length() > 0) {
            try {
                int value = Integer.parseInt(property);
                druidDataSource.setMaxWaitThreadCount(value);
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.maxWaitThreadCount'", e);
            }
        }

        property = properties.getProperty("druid.minEvictableIdleTimeMillis");
        if (property != null && property.length() > 0) {
            try {
                long value = Long.parseLong(property);
                druidDataSource.setMinEvictableIdleTimeMillis(value);
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.minEvictableIdleTimeMillis'", e);
            }
        }

        property = properties.getProperty("druid.useUnfairLock");
        Boolean value = null;
        if (Boolean.TRUE.toString().equalsIgnoreCase(property)) {
            value = Boolean.TRUE;
        } else if (Boolean.FALSE.toString().equalsIgnoreCase(property)) {
            value = Boolean.FALSE;
        }
        if (value != null) {
            druidDataSource.setUseUnfairLock(value);
        }

        property = properties.getProperty("druid.initialSize");
        if (property != null && property.length() > 0) {
            try {
                druidDataSource.setInitialSize(Integer.parseInt(property));
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.initialSize'", e);
            }
        }

        property = properties.getProperty("druid.minIdle");
        if (property != null && property.length() > 0) {
            try {
                druidDataSource.setMinIdle(Integer.parseInt(property));
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.minIdle'", e);
            }
        }

        property = properties.getProperty("druid.maxActive");
        if (property != null && property.length() > 0) {
            try {
                druidDataSource.setMaxActive(Integer.parseInt(property));
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.maxActive'", e);
            }
        }

        property = properties.getProperty("druid.maxWait");
        if (property != null) {
            druidDataSource.setMaxWait(Long.parseLong(property));
        }

        property = properties.getProperty("druid.connectProperties");
        if (property != null) {
            druidDataSource.setConnectionProperties(property);
        }

        property = properties.getProperty("druid.maxPoolPreparedStatementPerConnectionSize");
        if (property != null && property.length() > 0) {
            try {
                druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(Integer.parseInt(property));
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.maxPoolPreparedStatementPerConnectionSize'", e);
            }
        }

        property = properties.getProperty("druid.initConnectionSqls");
        if (property != null && property.length() > 0) {
            try {
                StringTokenizer tokenizer = new StringTokenizer(property, ";");
                druidDataSource.setConnectionInitSqls(Collections.list(tokenizer));
            } catch (NumberFormatException e) {
                log.error("illegal property 'druid.initConnectionSqls'", e);
            }
        }
    }
}
